//
//  MetaMaskRepo.swift
//  Co2DappHackson
//
//  Created by zhao on 2023/11/5.
//

import SwiftUI
import Combine
import metamask_ios_sdk
import HealthKit

extension Notification.Name {
    static let Connection = Notification.Name("connection")
}

class MetaMaskRepo: ObservableObject{
    
    @Published var connectionStatus = "Offline" {
        didSet{
            NotificationCenter.default.post(name: .Connection, object: nil,userInfo: ["value":connectionStatus])
        }
    }
    
    
    @Published var chainID = ""
    @Published var ethAddress = ""
    @Published var balance = ""
    @Published var stepCount = ""
    
   
    @Published  var etherum = MetaMaskSDK.shared.ethereum
    private let dappName = "Co2 Dapp"
    private let dappUrl = "https://qq.com/"
    
    private var cancellables: Set<AnyCancellable> = []
    
    let healthStore = HKHealthStore()
    
    init() {
        etherum.clearSession()
        etherum.disconnect()
        obseveConnecitonStatus()
    }
    
    private func obseveConnecitonStatus(){
        etherum.$connected
            .sink{ [weak self] isConnected in
                self?.connectionStatus = isConnected ? "Connected" : "Disconnected"
            }.store(in: &cancellables)
    }
    
    func connectToDapp(){
        let dapp = Dapp(name:dappName,url:dappUrl)
        etherum.connect(dapp)?
            .sink(receiveCompletion: { completion in
                switch completion {
                case .failure(let error):
                    
                    print( "connection error : \(error.localizedDescription)")
                default: break
                }
                
            }, receiveValue: { result in
                print( "connection result: \(result)")
                DispatchQueue.main.async {
                    self.chainID = self.etherum.chainId
                    self.ethAddress = self.etherum.selectedAddress
                }
            })
            .store(in: &cancellables)
    }
    
    func getBalance(){
        let parameters : [String] = [ethAddress,"latest"]
        
        let getBalaceRequest = EthereumRequest(method: .ethGetBalance,
                                                 params:  parameters)
        
        etherum.request(getBalaceRequest)?.sink(receiveCompletion: { completion in
            switch completion {
            case .failure(let error):
                print( "getBalance error : \(error.localizedDescription)")
            default: break
            }
        }, receiveValue: { result in
            print( "getBalance result: \(result)")
            //self.balance = result as! String
            DispatchQueue.main.async {
                let ethBalance = result as! String
                self.balance = "\(self.covertWeiToEth(hex: ethBalance)) ETH"
                print( "ethBalance: \(ethBalance)")
            }
        })
        .store(in: &cancellables)
    }
    
    func covertWeiToEth(hex:String) -> String{
        let scnner=Scanner(string: hex)
        var hexInt : UInt64 = 0
        scnner.scanHexInt64(&hexInt)
        var etherDecimal = Decimal(hexInt) / pow(10, 18)
        var roundedEtherDecimal = Decimal()
        NSDecimalRound(&roundedEtherDecimal, &etherDecimal, 5, .up)
        return roundedEtherDecimal.description
        
    }
    
    func authHealth(){
        let stepCount = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!
                       healthStore.requestAuthorization(toShare: nil, read: [stepCount]) { (success, error) in
                           if success {
                               // 用户已授权，可以获取步数数据
                               self.updateStepCount()
                           } else {
                               // 授权请求失败
                               print("授权请求失败：\(error?.localizedDescription ?? "Unknown error")")
                           }
                       }
        print("authHealth: \(stepCount)")
    }
    
    func updateStepCount() {
                // 获取步数数据
                let sampleType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!
                let calendar = Calendar.current
                let now = Date()
                let startDate = calendar.startOfDay(for: now)
                let predicate = HKQuery.predicateForSamples(withStart: startDate, end: now, options: .strictEndDate)

                let query = HKStatisticsQuery(quantityType: sampleType, quantitySamplePredicate: predicate, options: .cumulativeSum) { (query, result, error) in
                    guard let result = result, let sum = result.sumQuantity() else {
                        if let error = error {
                            // 查询失败
                            print("查询失败：\(error.localizedDescription)")
                        }
                        return
                    }

                    let totalSteps = sum.doubleValue(for: HKUnit.count())
                    // 在这里更新 UI，显示步数数据
                    DispatchQueue.main.async {
                        self.stepCount = "\(totalSteps) steps"
                    }
                }

                healthStore.execute(query)
    }
    func callContract() {
        print("callContract")
        // parameters 参数值 "params":[{"to":"合约地址","data":"方法调用数据"}, "latest"]
     //   let parameters : [String] = [{"to": "0xFdb0Bb0649Ba691C3EF41af94D741d494DAd30A1"},"latest"]
//        let parameters : [String: String] = [
//            "to": "0xFdb0Bb0649Ba691C3EF41af94D741d494DAd30A1", // receiver address
//             "data": "retrieve" // function name
//        ]
        let parameters: [String: String] = [
            "to": "0xFdb0Bb0649Ba691C3EF41af94D741d494DAd30A1",
            "data": "retrieve",
            "block": "latest"
        ]
        
        let retrieveRequest = EthereumRequest(method: .ethCall,
                                                 params:  parameters)
        
        etherum.request(retrieveRequest)?.sink(receiveCompletion: { completion in
            switch completion {
            case .failure(let error):
                print( "callCon error : \(error.localizedDescription)")
            default: break
            }
        }, receiveValue: { result in
            print( "callCon result: \(result)")
            //self.balance = result as! String
//            DispatchQueue.main.async {
//                let ethBalance = result as! String
//                self.balance = "\(self.covertWeiToEth(hex: ethBalance)) ETH"
//                print( "ethBalance: \(ethBalance)")
//            }
        })
        .store(in: &cancellables)
    }
    
    func send(){
        let to = "0xB6155959482afFD22e5482e6e1703fBCE88b089e"
        let transaction = Transaction(
            to: to,
            from: self.ethAddress,
            value: "0.001"
        )

        let transactionRequest = EthereumRequest(
            method: .ethSendTransaction,
            params: [transaction] // eth_sendTransaction rpc call expects an array parameters object
        )

        etherum.request(transactionRequest)?.sink(receiveCompletion: { completion in
            switch completion {
            case let .failure(error):
//                errorMessage = error.localizedDescription
//                showError = true
                print("Transaction error: \(error.localizedDescription)")
            default: break
            }
        }, receiveValue: { value in
            print("Transaction result: \(value)")
           // self.result = value as? String ?? ""
        }).store(in: &cancellables)
    }
}

struct Transaction: CodableData {
    let to: String
    let from: String
    let value: String
    let data: String?

    init(to: String, from: String, value: String, data: String? = nil) {
        self.to = to
        self.from = from
        self.value = value
        self.data = data
    }

    func socketRepresentation() -> NetworkData {
        [
            "to": to,
            "from": from,
            "value": value,
            "data": data
        ]
    }
}
